package ochart.core
{
	import caurina.transitions.Tweener;
	
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	import ochart.elements.DataElement;
	import ochart.elements.background.BackgroundBase;
	import ochart.elements.bars.Bar;
	import ochart.elements.labels.DataTip;
	import ochart.elements.labels.LabelBase;
	import ochart.utils.ArrayUtil;
	
	public class ChartBase extends ChartObject implements IChart
	{
		public static const CLASS_NAME:String = "ChartBase";
		
		override public function get className():String
		{
			return CLASS_NAME;
		}
		
		public static const ALIAS:String = "chartBase";
		
		override public function get alias():String
		{
			return ALIAS;
		}
		
		public var dataTipContainer:ChartObject = null;
		public var titleContainer:ChartObject = null;
		public var legendsContainer:ChartObject = null;
		public var elementsContainer:ChartObject = null;
		public var axesContainer:ChartObject = null;
		public var gridContainer:ChartObject = null;
		
		protected var isTitleChange:Boolean = false;
		private var _title:LabelBase = null;
		
		public function get title():LabelBase
		{
			return _title;
		}
		
		public function set title(value:LabelBase):void
		{
			_title = value;
			
			isTitleChange = true;
			needUpdate = true;
		}
		
		public var isDataTipChange:Boolean = false;
		private var _dataTip:DataTip = null;

		public function get dataTip():DataTip
		{
			return _dataTip;
		}

		public function set dataTip(value:DataTip):void
		{
			_dataTip = value;
			if(_dataTip)
			{
				_dataTip.alpha = 0;
			}
			isDataTipChange = true;
			needUpdate = true;
		}
		
		public var isElementChange:Boolean = false;
		private var _elementsArray:Array = [];

		public function get elementsArray():Array
		{
			return _elementsArray;
		}

		public function set elementsArray(value:Array):void
		{
			_elementsArray = value;
			
			isElementChange = true;
			needUpdate = true;
		}
		
		public var dataElementsArray:Array = [];
		
		private var defaultValue:Object = 
		{
			
		}
			
		private var _propertiesArray:Array = null;
		
		override public function get propertiesArray():Array
		{
			if(_propertiesArray)
			{
				return _propertiesArray;
			}
			
			_propertiesArray = super.propertiesArray;
			for(var name:String in defaultValue)
			{
				if(!ArrayUtil.containsValue(_propertiesArray, name))
				{
					_propertiesArray.push(name);
				}
			}
			return _propertiesArray;
		}
		
		public function ChartBase()
		{
			super();
			
			addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
			addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
			addEventListener(MouseEvent.ROLL_OUT, onMouseOut);
		}
		
		override public function init():void
		{
			super.init();
			
			dataTipContainer = new ChartObject();
			titleContainer = new ChartObject();
			legendsContainer = new ChartObject();
			elementsContainer = new ChartObject();
			axesContainer = new ChartObject();
			gridContainer = new ChartObject();
			
			dataTipContainer.relateToParent = true;
			titleContainer.relateToParent = true;
			legendsContainer.relateToParent = true;
			elementsContainer.relateToParent = true;
			axesContainer.relateToParent = true;
			gridContainer.relateToParent = true;
			
			addChild(gridContainer);
			addChild(axesContainer);
			addChild(elementsContainer);
			addChild(legendsContainer);
			addChild(titleContainer);
			addChild(dataTipContainer);
		}
		
		override public function getDefaultValue(name:String):*
		{
			return (defaultValue[name] === undefined) ? super.getDefaultValue(name) : defaultValue[name];
		}
		
		override public function update(callAfterUpdate:Boolean=true):Boolean
		{
			if(!super.update(false))
			{
				return false;
			}
			
			if(isTitleChange)
			{
				isTitleChange = false;
				titleContainer.clear();
				titleContainer.addChild(title);
			}
			
			if(isDataTipChange)
			{
				isDataTipChange = false;
				dataTipContainer.clear();
				dataTipContainer.addChild(dataTip);
			}
			
			if(callAfterUpdate)
			{
				return afterUpdate();
			}
			return true;
		}
		
		override public function destory():void
		{
			super.destory();
			removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
		}
		
		protected function onMouseMove(event:MouseEvent):void
		{
			if(dataTip)
			{
				var targetsArray:Array =[];
				if(event.target is DataElement)
				{
					targetsArray = [event.target]
				}
				else if(dataTip.seekMode == DataTip.CLOSEST)
				{
					var mousePoint:Point = new Point(mouseX, mouseY);
					var nearestDataElementsArray:Array = [];
					var nearest:Number = Number.MAX_VALUE;
					for each(var nearestDataElement:DataElement in dataElementsArray)
					{
						var nearestPoint:Point = nearestDataElement.localToGlobal(new Point(nearestDataElement.centerX, nearestDataElement.middleY));
						var nearestValue:Number = Math.abs(nearestPoint.x - mousePoint.x);
						if(nearestValue <= nearest)
						{
							if(nearestValue < nearest)
							{
								nearest = nearestValue;
								nearestDataElementsArray = [];
							}
							nearestDataElementsArray.push(nearestDataElement);
						}
					}

					var minSpaceDataElementsArray:Array = []
					var minSpace:Number = Number.MAX_VALUE;
					var spaceIndex:int = 0;
					for each(var dataElement:DataElement in nearestDataElementsArray)
					{
						var space:Number = dataElement.evaluateSpace(mousePoint);
						if(space > -1 && space <= minSpace)
						{
							if(space < minSpace)
							{
								minSpace = space;
								minSpaceDataElementsArray = [];
							}
							minSpaceDataElementsArray.push(dataElement);
						}
						spaceIndex++;
					}
					targetsArray = minSpaceDataElementsArray;
				}
				
				if(targetsArray.length > 0)
				{
					dataTip.show();
					dataTip.targetsArray = targetsArray;
					var targetPoint:Point = (targetsArray[0] as DataElement).localToGlobal(new Point(0, 0));
					Tweener.addTween(dataTip, {x:(targetPoint.x), y:(targetPoint.y - dataTip.totalHeight), time:0.5});
				}
				else
				{
					dataTip.hide();
				}
			}
		}
		
		protected function onMouseOut(event:MouseEvent):void
		{
			if(dataTip && event.target == this)
			{
				dataTip.hide();
			}
		}
	}
}